define('tesla-mobile', [ 'juicer' ], function(require, exports, module){

	var juicer = require("juicer"),
		Tesla = function() {
            this.BASE_PATH = "./../";
            this.SERVICE_PREFIX = "";
            this.TMPL_PATH = "tpl/";
            this.DEFAULT_CONTAINER_ID = "sys-container";
            this.COMPONENT_PACKAGE = "scm/components/";
        },
        PAGE_SELECTOR = "[data-box]";

	Tesla.fn = Tesla.prototype = {};


	Tesla.fn.load = function(action, param, container, target) {
		require.async(this.resolveScriptUrl(action), function(controller) {
			container =  (container || $("#" + $ts.DEFAULT_CONTAINER_ID));

			var config 	= new ConfigHandler(controller, action, param),
				handler = new ActionHandler(config, param, container, target),
				render 	= function() {
					if (typeof (config.handle) === "undefined") {
						handler.render();
					} else {
						config.handle.call(controller, handler);
					}
				};

			if (config.service && config.service.length > 0) {
				$ts.ajaxJSON(config.service, config.method, handler.param).done(function(result) {
					handler.model = result;
					render();
				});
			} else {
				render();
			}
			
			container.show();
		});
	};

	Tesla.fn.submit = function(action) {
		var _e 		= getEvent(),
			_form 	= $(_e.currentTarget).closest("form"),
			_data 	= {},
			_arr 	= _form.formToArray();

		_e.preventDefault();
		
		if (action.indexOf(".") < 0) {
			action = _form.closest(PAGE_SELECTOR).data("controller") + "." + action;
		}

		for (var i = 0, item; (item = _arr[i]) != null; i++) {
			if (item.type === "checkbox") {
				if (!_data[item.name]) {
					_data[item.name] = [];
				}
				_data[item.name].push(item.value);
			} else {
				_data[item.name] = item.value;
			}
		}

		this.load(action, _data, undefined, _e);
	};

	Tesla.fn.call = function(action, param) {
		var _target 	= $(getEvent().currentTarget),
			_this 		= this,
			_container 	= _target.closest(PAGE_SELECTOR);
		
		if (!_container.length) {
			_container = $("#" + this.DEFAULT_CONTAINER_ID);
		}
		
		if (action.indexOf(".") < 0) {
			action = _container.data("controller") + "." + action;
		}
		
		this.getAction(action).done(function (controller) {
			var _actionName = _this.getActionName(action),
				_handle = controller[_actionName];
			
			if (_handle) {
				_handle.call(controller, _target, _container, param);
			}
		});
	};

	Tesla.fn.link = function(action, param) {
		var _target = $(getEvent().currentTarget);
		
		if (action.indexOf(".") < 0) {
			action = _target.closest(PAGE_SELECTOR).data("controller") + "." + action;
		}
		
		this.load(action, param, _target.closest(PAGE_SELECTOR));
	};

	Tesla.fn.compile = function(html, data) {
		var template = juicer(html, data);
		return $(template);
	};
    /*
    * component:ajax
    * author:zhoujj
    * date:2014-09-01
    * */
    Tesla.fn.ajaxJSON = function(service, type, param) {
        var _def = $.Deferred();

        $.ajax({
            url : this.getServicePath(service),
            data : type.toUpperCase() === "GET" ?  param : JSON.stringify(param),
            dataType : "json",
            type : type,
            contentType : "application/json;charset=UTF-8",
            success : function(result) {
                if (result.returnCode.code === "AAAAAA") {
                    _def.resolve(result.reply);
                } else {
                    _def.reject(result);
                }
            },
            error : function(result) {
                _def.reject(result);
            },
            cache :false
        });
        return _def.promise();
    };

    Tesla.fn.postJSON = function(service,param){
        return this.ajaxJSON(service,"POST",param);
    };

    Tesla.fn.getJSON = function(service,param){
    	return this.ajaxJSON(service,"GET",param);
    };

    Tesla.fn.getJSON = function(service,param){
    	return this.ajaxJSON(service,"PUT",param);
    };

    Tesla.fn.getJSON = function(service,param){
    	return this.ajaxJSON(service,"DELETE",param);
    };



	Tesla.fn.getActionName = function(action) {
		if (action.indexOf(".") < 0)
			return action;
		
		return action.substr(action.lastIndexOf(".") + 1);
	};

	Tesla.fn.getAction = function(action) {
		var _def = $.Deferred();
		
		require.async(this.resolveScriptUrl(action), function(controller) {
			_def.resolve(controller);
		});
		
		return _def.promise();
	};
	
	Tesla.fn.getServicePath = function(service) {
		return this.SERVICE_PREFIX + service;
	};

	Tesla.fn.resolveScriptUrl = function(action) {
		return this.BASE_PATH + this.TMPL_PATH
				+ action.substring(0, action.lastIndexOf(".")).replace(/\./g, "/")
				+ "/controller.js";
	};
	
	/**
	 * @param str ?param1=1&param2=2类似这种格式的字符串，如果不传默认为location。search
	 * @description 该方法将传入的search字符串转换为对象，暂时不支持数组参数的解析，存在相同名字的参数会覆盖
	 * @return param 
	 */
	Tesla.fn.resolveSearch = function(str) {
		var arr,
			param = {};
		
		if (!str) {
			str = location.search;
		}
		
		str = str ? str.substr(1) : "";
		arr = str.split("&");
		
		for (var i = 0, item; (item = arr[i]) != null; i++) {
			var tmp = item.split("=");
			param[tmp[0]] = tmp[1];
		}
		
		return param;
	};

	function ConfigHandler(controller, action, param) {
		var _name = action.substr(action.lastIndexOf(".") + 1),
		    _namespace = action.substring(0, action.lastIndexOf(".")),
		    _config = controller.config[_name] || {};
		
		param = param || {};
		$.extend(param, _config["defaultParam"]);
		
		var _retObj = {
			name : _name,
			namespace : _namespace,
			action : action,
			view : _config["view"] || _name,
			service : resolveServiceStr(_config["service"], param),
			method : _config["method"] || "GET",
			handle : controller[_name],
			param : param
		};
		
		return _retObj;
	}

	function ActionHandler(config, param, container, target) {
		this.param = config.param;
		this.model = {};
		this.view = undefined;
		this.target = target;
		this.config = config;
		this.container = container;
	}
	
	ActionHandler.prototype = {
			refresh : function() {
				$ts.load(this.config.action, this.param, this.view);
			},	
			navigateTo : function(action, param) {
				if (!this.view) {
					this.view = $(this.target).closest(PAGE_SELECTOR);
				}
				
				$ts.load(action.indexOf(".") < 0 ? this.config.namespace + "." + action : action, param, this.view);
			},
			render : function(callback) {
				var viewPath = $ts.TMPL_PATH + this.config.namespace.replace(/\./g, "/") + "/" + this.config.view + ".html",
                    data = {
                        param : this.param,
                        model : this.model
                    },
                    _this = this;

				$.ajax(viewPath, {
					success : 	function(result) {
									_this.view = $ts.compile("<div data-box='"+_this.config.namespace+"'>" + result + "</div>", data);
									_this.view.data("controller", _this.config.namespace);
									
									if (typeof (callback) === "undefined") {
										_this.renderEnd();
									} else {
										callback();
									}
								},
					dataType : "html"
				});
			},
			_renderComponent : function() {
                var _this = this;
                
				this.view.find("[ts-type]").each(function(index, com) {
					var _types = $(this).attr("ts-type").split(" ");
					
					for (var i = _types.length; i--;) {
						var _type = _types[i];
						require.async($ts.COMPONENT_PACKAGE + _type, function(Component) {
							Component.init($(com), _this.model, _this.param, $ts);
						});
					}
				});
			},
			renderEnd : function() {
				this._renderComponent();
				if (this.container.attr("data-box")) {
					this.container.after(this.view);
					this.container.remove();
				} else {
					this.container.empty();
					this.container.append(this.view);
				}
			}
	};

	function resolveServiceStr(service, param){
		if (!service)
			return service;
		return juicer(service, {param : param});
	}
	
	function getEvent() {
		if (window.event) {
			return $.event.fix(window.event);
		}
		
		var f = arguments.callee;
		
		while(f = f.caller) {
			var e = f.arguments[0];
			
			if (e instanceof Event || e instanceof $.Event) {
				return $.event.fix(e);
			}
		};
	}

	var $ts = new Tesla();
	module.exports = $ts;
});